<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
	<title></title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
	<script type="text/javascript">
	// <!--
	/*
	This file is really focused on just sending one message to the server, and
	receiving one response. The code does not expect to be re-used for multiple messages.
	This might be reworked later if performance indicates a need for it.
	
	xip fragment identifier/hash values have the form:
	#id:cmd:realUrlEncodedMessage

	id: some ID that should be unique among messages. No inherent meaning,
	        just something to make sure the hash value is unique so the message
	        receiver knows a new message is available.
	        
	cmd: command to the receiver. Valid values are:
	         - loaded: the remote frame is loaded. Only sent from server to client.
	         - ok: the message that this page sent was received OK. The next message may
	               now be sent.
	         - start: the start message of a block of messages (a complete message may
	                  need to be segmented into many messages to get around the limitiations
	                  of the size of an URL that a browser accepts.
	         - part: indicates this is a part of a message.
	         - end: the end message of a block of messages. The message can now be acted upon.
	                If the message is small enough that it doesn't need to be segmented, then
	                just one hash value message can be sent with "end" as the command.
	
	To reassemble a segmented message, the realUrlEncodedMessage parts just have to be concatenated
	together.
	*/

	//Choosing 1024 as an arbitrary limit for the URL sizes.
	//Anecdotal info seems to indicate this is safe to use in all
	//modern browsers.
	xipUrlLimit = 1024;
	xipIdCounter = 1;

	function xipInit(){
		xipIsSending = false;
		xipServerUrl = null;
		xipStateId = null;
		xipRequestData = null;
		xipCurrentHash = "";
		xipResponseMessage = "";
		xipRequestParts = [];
		xipPartIndex = 0;
		xipServerWindow = null;
	}
	xipInit();
	
	function send(stateId, ifpServerUrl, urlEncodedData){
		if(!xipIsSending){
			xipIsSending = true;

			xipStateId = stateId;
			xipRequestData = urlEncodedData || "";

			//Modify the server URL if it is a local path and 
			//This is done for local/same domain testing.
			xipServerUrl = ifpServerUrl;
			if(ifpServerUrl.indexOf("..") == 0){
				var parts = ifpServerUrl.split("/");
				xipServerUrl = parts[parts.length - 1];
			}

			//Fix server URL to tell it about this page's URL. So that it can call us
			//back correctly. Use the fragment identifier to allow for caching of the server
			//page, and hey, we're using the fragment identifier for everything else.
			ifpServerUrl += "#" + encodeURIComponent(window.location);	

			//Start counter to inspect hash value.
			setInterval(pollHash, 10);

			//Loader server iframe, then wait for the server page to call us back.
			xipServerWindow = frames["xipServerFrame"];
			if (!xipServerWindow){
				xipServerWindow = document.getElementById("xipServerFrame").contentWindow;
			}

			xipServerWindow.location.replace(ifpServerUrl);
		}
	}

	function pollHash(){
		//Can't use location.hash because at least Firefox does a decodeURIComponent on it.
		var urlParts = window.location.href.split("#");
		if(urlParts.length == 2){
			var newHash = urlParts[1];
			if(newHash != xipCurrentHash){
				try{
					messageReceived(newHash);
				}catch(e){
					//Make sure to not keep processing the error hash value.
					xipCurrentHash = newHash;
					throw e;
				}
				xipCurrentHash = newHash;
			}
		}
	}

	function messageReceived(urlEncodedMessage){
		//Split off xip header.
		var parts = urlEncodedMessage.split(":");
		var command = parts[1];
		urlEncodedMessage = parts[2] || "";
		
		switch(command){
			case "loaded":
				sendRequestStart();
				break;
			case "ok":
				sendRequestPart();
				break;
			case "start":
				xipResponseMessage = "";
				xipResponseMessage += urlEncodedMessage;
				setServerUrl("ok");
				break;
			case "part":
				xipResponseMessage += urlEncodedMessage;			
				setServerUrl("ok");
				break;
			case "end":
				setServerUrl("ok");
				xipResponseMessage += urlEncodedMessage;
				parent.dojo.io.XhrIframeProxy.receive(xipStateId, xipResponseMessage);
				break;
		}
	}
	
	function sendRequestStart(){
		//Break the message into parts, if necessary.
		xipRequestParts = [];
		var reqData = xipRequestData;
		var urlLength = xipServerUrl.length;
		var partLength = xipUrlLimit - urlLength;
		var reqIndex = 0;

		while((reqData.length - reqIndex) + urlLength > xipUrlLimit){
			xipRequestParts.push(reqData.substring(reqIndex, reqIndex + partLength));
			reqIndex += partLength;
		}
		xipRequestParts.push(reqData.substring(reqIndex, reqData.length));
		
		xipPartIndex = 0;
		sendRequestPart();
		
	}
	
	function sendRequestPart(){
		if(xipPartIndex < xipRequestParts.length){
			//Get the message part.
			var partData = xipRequestParts[xipPartIndex];

			//Get the command.
			var cmd = "part";
			if(xipPartIndex + 1 == xipRequestParts.length){
				cmd = "end";
			}else if (xipPartIndex == 0){
				cmd = "start";
			}
			
			setServerUrl(cmd, partData);
			xipPartIndex++;
		}
	}
	
	function setServerUrl(cmd, message){
		var serverUrl = xipServerUrl + "#" + (xipIdCounter++) + ":" + cmd;
		if(message){
			serverUrl += ":" + message;
		}

		//Safari won't let us replace across domains.
		if(navigator.userAgent.indexOf("Safari") == -1){
			xipServerWindow.location.replace(serverUrl);
		}else{
			xipServerWindow.location = serverUrl;
		}

	}
	// -->
	</script>
</head>
<body>
	<h4>The Dojo Toolkit -- xip_client.html</h4>

	<p>This file is used for Dojo's XMLHttpRequest Iframe Proxy. This is the "client" file used
	internally by dojo.io.XhrIframeProxy.</p>
	
	<iframe id="xipServerFrame"></iframe>
</body>
</html>
